package cn.edu.sjtu.software.sjtucontacts.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.edu.sjtu.software.sjtucontacts.model.Contact;
import cn.edu.sjtu.software.sjtucontacts.model.Group;

public class ListUtil {
	private Map<String, List<Contact>> contactList;
	private List<Contact> recentcontactList;
	private List<Group> groupList;
	private List<Integer> shareList;
	
	private static ListUtil listutil;
	
	private ListUtil() {
		initList();
	}
	
	private void initList() {
		contactList = new HashMap<String, List<Contact> >();
		recentcontactList = new ArrayList<Contact>();
		groupList = new ArrayList<Group>();
		shareList = new ArrayList<Integer>();
		
		contactList.clear();
		recentcontactList.clear();
		groupList.clear();
		shareList.clear();
	}
	
	/*
	 * First, you should invoke getInstace() method 
	 * to get a static object of ListUtil class
	 */
	public static ListUtil getInstance() {
		if(listutil == null) {
			listutil = new ListUtil();
		}
		
		return listutil;
	}
	
	public Map<String, List<Contact>> getContactList() {
		return contactList;
	}
	
	public List<Contact> getRecentContactList() {
		return recentcontactList;
	}
	
	public List<Group> getGroupList() {
		return groupList;
	}
	
	/*
	 * If there is not a group in the group list matched, return -1
	 * else return id of the group matched
	 */
	public int findGroupIdByName(String name) {
		int id = -1;
		for(int i = 0; i < groupList.size(); i++) {
			if(groupList.get(i).getName().equals(name)) {
				id = groupList.get(i).getId();
				break;
			}
		}
		return id;
	}
	
	/*
	 * Find the group reference by the given id
	 * if there is not any group matched, return null 
	 */
	public Group findGroupById(int id) {
		Group group = null;
		for(int i = 0; i < groupList.size(); i++) {
			if(groupList.get(i).getId() == id) {
				group = groupList.get(i);
				return group;
			}
		}
		
		return group;
	}
	
	/*
	 * If there is not a contact in the contactlist, return null
	 * else return contact found
	 * return a new copy of contact
	 */
	public Contact findContactById(int id) {
		Contact contact = null;
		List<Contact> colist = fetchContactList();
		for(int i = 0; i < colist.size(); i++) {
			if(colist.get(i).getId() == id) {
				contact = colist.get(i);
				return contact;
			}
		}
		
		return contact;
	}

	/*
	 * Update the contact list in a group
	 * First get the group by group id 
	 * Then add contact id to contact list
	 */
	public void addContactToGroup(int contactId, int groupId) {
		for(int i = 0; i < groupList.size(); i++) {
			if(groupList.get(i).getId() == groupId) {
				groupList.get(i).addContact(contactId);
				break;
			}
		}
	}
	
	public void deleteContactFromGroup(int contactId, int groupId) {
		for(int i = 0; i < groupList.size(); i++) {
			if(groupList.get(i).getId() == groupId) {
				System.out.println("Remove groupid: " + groupId);
				groupList.get(i).removeContact(contactId);
			}
		}
	}
	
	public void changeContactToGroup(int contactId, int groupId1, int groupId2) {
		System.out.println("into changContactToGroup "+groupId1+" "+groupId2);
		int group1Index = -1;
		int group2Index = -1;
		for(int i = 0; i< groupList.size(); i++) {
			int id = groupList.get(i).getId();
			if(id == groupId1) {
				group1Index = i;
			}
			if(id == groupId2) {
				group2Index = i;
			}
		}
		if(group1Index != -1 && group2Index != -1) {
			groupList.get(group1Index).removeContact(contactId);
			groupList.get(group2Index).addContact(contactId);
			System.out.println("changContactToGroup Success!");
		}
	}
	
	public List<Contact> fetchContactList()
    {
    	List<Contact> contactArrayList = new ArrayList<Contact>();
    	Set<String> ketSet = contactList.keySet();
    	Iterator<String> iterator = ketSet.iterator();
    	while (iterator.hasNext()) {
    		contactArrayList.addAll(contactList.get(iterator.next()));
    	}
    	return contactArrayList;
    }
	
	public void addContactToContactList(Contact contact) {
//		String firstCharString =contact.getFirstName().substring(0,1).toLowerCase();
//    	if (firstCharString.matches("[\\u4E00-\\u9FA5]+")) {
//    		firstCharString = String.valueOf(new StringUtil().convert(contact.getFirstName())).toLowerCase();
//    	}
//		List<Contact> value = contactList.get(firstCharString);	
//		if (value == null) {
//			value = new ArrayList<Contact>();	
//			contactList.put(firstCharString, value);
//		}
//		value.add(contact);	
		addContactToContactListByProperty(contact, contact.getFirstName());
			
	}    
	
    public void deleteContactFromContactList (Contact contact)
    {
    	String firstCharString =contact.getFirstName().substring(0,1).toLowerCase();
    	if (firstCharString.matches("[\\u4E00-\\u9FA5]+")) {
    		firstCharString = String.valueOf(new StringUtil().convert(contact.getFirstName())).toLowerCase();
    	}
    	List<Contact> value = contactList.get(firstCharString);	
    	if (value != null) {
    		Iterator<Contact> iter = value.iterator();
    		while (iter.hasNext()) {
    			if (iter.next().getId() == contact.getId()) {
    				iter.remove();
    				ContactIDGenerator.recyleId(contact.getId());
    				break;
    			}
    		}
    		
    		// All contacts beginning with some letter are deleted
    		if (value.size() == 0) {
    			contactList.remove(firstCharString);
    		} 
    	}
    }
    
    public void updateContactIntoContactList (Contact contact)
    {
    	String firstCharString =contact.getFirstName().substring(0,1).toLowerCase();
    	if (firstCharString.matches("[\\u4E00-\\u9FA5]+")) {
    		firstCharString = String.valueOf(new StringUtil().convert(contact.getFirstName())).toLowerCase();
    	}
    	List<Contact> value = contactList.get(firstCharString);
    	Contact tempContact = null;
    	if (value != null) {
    		Iterator<Contact> iter = value.iterator();
    		boolean isFound = false;
    		while (iter.hasNext()) {
    			tempContact = iter.next();
    			if (tempContact.getId() == contact.getId()) {
    				iter.remove();
    				isFound = true;
    				break;
    			}
    		}
    		
    		if (isFound) {
    			value.add(contact);
    		}    				
    	}
    }
    
    public void addContactToRecentList(Contact contact) {
    	recentcontactList.add(contact);
    }
    
    public void deleteContactFromRecentList(Contact contact) {
    	recentcontactList.remove(contact);
    }
    
    public void addGroupToGroupList(Group group) {
    	groupList.add(group);
    }
    
    public void deleteGroupFromGroupList(Group group) {
    	groupList.remove(group);
    }    
    
    public void sortContactList(int criterion) {
    	try {
	    	HashMap<String, List<Contact> > sortedMap = new HashMap<String, List<Contact>>();
	    	Set keySet = contactList.keySet();
	    	Iterator<String> iterator = keySet.iterator();
	    	
	    	switch (criterion) {
	    	case 0:
	    		while (iterator.hasNext()) {
	    			List<Contact> value = contactList.get(iterator.next());
	    			Iterator<Contact> cIter = value.iterator();
	    			while (cIter.hasNext()) {
	    				Contact contact = cIter.next();
	    				addContactToContactListByProperty(sortedMap, contact, contact.getFirstName());
	    			}        		
	        	}
	    		break;
	    	case 1:
	    		while (iterator.hasNext()) {
	    			List<Contact> value = contactList.get(iterator.next());
	    			Iterator<Contact> cIter = value.iterator();
	    			while (cIter.hasNext()) {
	    				Contact contact = cIter.next();
	    				addContactToContactListByWorkAddress(sortedMap, contact);
	    			}
	        	}
	    		changeToPingYinMode(sortedMap);
	    		break;
	    	case 2:
	    		while (iterator.hasNext()) {
	    			List<Contact> value = contactList.get(iterator.next());
	    			Iterator<Contact> cIter = value.iterator();
	    			while (cIter.hasNext()) {
	    				Contact contact = cIter.next();
	    				addContactToContactListByJob(sortedMap, contact);
	    			}
	        	}
	    		break;    	
	    	case 3:
	    		while (iterator.hasNext()) {
	    			List<Contact> value = contactList.get(iterator.next());
	    			Iterator<Contact> cIter = value.iterator();
	    			while (cIter.hasNext()) {
	    				Contact contact = cIter.next();
	    				addContactToContactListByBirthday(sortedMap, contact, contact.getBirthday());
	    			}
	        	}
	    		break;
	    	default:
	    		break;
	    	}
	    	
	    	contactList.clear();
	    	contactList.putAll(sortedMap);
    	} catch (Exception e) {
    		e.printStackTrace();    		
    	}    	
    }
    
    /**
     * change change the key to the ping yin form
	 * @param sortedMap
	 */
	private void changeToPingYinMode(HashMap<String, List<Contact>> sortedMap) {
		HashMap<String, List<Contact>> tempMap = new HashMap<String, List<Contact>>();
		Set<String> keySet = sortedMap.keySet();
		Iterator<String> keyIterator = keySet.iterator();
		StringUtil util = new StringUtil();
		while (keyIterator.hasNext()) {
			String key = keyIterator.next();
			String pingYinKey = util.getPingYin(key);
			tempMap.put(pingYinKey, sortedMap.get(key));			
		}
		sortedMap.clear();
		sortedMap.putAll(tempMap);
	}

	private void addContactToContactListByProperty(Contact contact, String property) {
    	String firstCharString = property.substring(0,1).toLowerCase();
    	if (firstCharString.matches("[\\u4E00-\\u9FA5]+")) {
    		firstCharString = String.valueOf(new StringUtil().convert(property)).toLowerCase();
    	}
		List<Contact> value = contactList.get(firstCharString);	
		if (value == null) {
			value = new ArrayList<Contact>();	
			contactList.put(firstCharString, value);
		}
		value.add(contact);	
    }
    
    private void addContactToContactListByProperty (HashMap<String, List<Contact>> map, Contact contact, String property) throws IllegalArgumentException 
    {    
    	if (property == null || property.length() == 0
    			|| contact == null || map == null) {
    		throw new IllegalArgumentException();
    	}
    	String firstCharString = property.substring(0,1).toLowerCase();
    	if (firstCharString.matches("[\\u4E00-\\u9FA5]+")) {
    		firstCharString = String.valueOf(new StringUtil().convert(property)).toLowerCase();
    	}
		List<Contact> value = map.get(firstCharString);	
		if (value == null) {
			value = new ArrayList<Contact>();	
			map.put(firstCharString, value);
		}
		value.add(contact);	
    }
    
    private void addContactToContactListByBirthday (HashMap<String, List<Contact>> map, Contact contact, String birthday) throws IllegalArgumentException 
    {    
    	if (birthday == null || birthday.length() == 0
    			|| contact == null || map == null) {
    		throw new IllegalArgumentException();
    	}
    	String[] ymd = birthday.split("-");
		List<Contact> value = map.get(ymd[1]);	
		if (value == null) {
			value = new ArrayList<Contact>();	
			map.put(ymd[1], value);
			
		}
		value.add(contact);
		Comparator<Contact>  comparator = new Comparator<Contact>() {

			@Override
			public int compare(Contact arg0, Contact arg1) {
				try {
					String[] ymd0 = arg0.getBirthday().split("-");
					String[] ymd1 = arg0.getBirthday().split("-");
					int month0 = Integer.parseInt(ymd0[1]);
					int month1 = Integer.parseInt(ymd1[1]);
					return month0 > month1 ? 1 : -1;
				} catch (Exception e) {
					e.printStackTrace();
				}
				return 1;
			}
			
		};
		Collections.sort(value,  comparator);
    }
    
    private void addContactToContactListByWorkAddress(HashMap<String, List<Contact>> map, Contact contact) 
    throws IllegalArgumentException {
    	if (map == null || contact == null) {
    		throw new IllegalArgumentException();
    	} 
    	if (contact.getWorkAddress() == null) {
    		throw new IllegalArgumentException();
    	}
    	StringUtil stringUtil = new StringUtil();
    	String pingYinForm = contact.getWorkAddress();
    	List<Contact> listOfContact = map.get(pingYinForm);    	
    	if (listOfContact == null) {
    		listOfContact = new ArrayList<Contact>();
    		map.put(pingYinForm, listOfContact);    		
    	}
    	listOfContact.add(contact);
    }   
    
    private void addContactToContactListByJob(HashMap<String, List<Contact>> map, Contact contact) 
    throws IllegalArgumentException {
    	if (map == null || contact == null) {
    		throw new IllegalArgumentException();
    	} 
    	if (contact.getWorkAddress() == null) {
    		throw new IllegalArgumentException();
    	}
    	StringUtil stringUtil = new StringUtil();
    	String pingYinForm = contact.getJob();
    	List<Contact> listOfContact = map.get(pingYinForm);    	
    	if (listOfContact == null) {
    		listOfContact = new ArrayList<Contact>();
    		map.put(pingYinForm, listOfContact);    		
    	}
    	listOfContact.add(contact);
    }

	public List<Integer> getShareList() {
		// TODO Auto-generated method stub
		return shareList;
	}

	public void clearShareList() {
		// TODO Auto-generated method stub
		shareList.clear();
	}

	public void addContactToShareList(int pos) {
		// TODO Auto-generated method stub
		shareList.add(pos);
	}

	public void removeContactFromShareList(int pos) {
		// TODO Auto-generated method stub
		for(int i=0; i<shareList.size(); i++) {
			if(shareList.get(i) == pos) {
				shareList.remove(i);
			}
		}
	}   
	
	public void filterContactList(String name) {
		
	}
	
	public void clearList(){
		contactList.clear();
		recentcontactList.clear();
		groupList.clear();
		shareList.clear();
	}
	
	public void clearContactList() {
		contactList.clear();
	}
   
	public void clearGroupList() {
		groupList.clear();
	}
}
